package io.zjw.testblelib;

import android.annotation.SuppressLint;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.LinearSnapHelper;
import android.support.v7.widget.RecyclerView;
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

import com.github.mikephil.charting.charts.LineChart;
import com.github.mikephil.charting.components.LimitLine;
import com.github.mikephil.charting.components.XAxis;
import com.github.mikephil.charting.components.YAxis;
import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.data.LineData;
import com.github.mikephil.charting.data.LineDataSet;
import com.github.mikephil.charting.interfaces.datasets.ILineDataSet;
import com.yuanxu.ecg.L;

import org.apache.fontbox.afm.CompositePart;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ConcurrentLinkedQueue;

public class EEGActivity extends AppCompatActivity implements View.OnClickListener {

    private final String TAG = "EEGActivity";
    //连接状态标志
    private boolean isConnected = false;
    //连接状态--已连接
    private final String CONNECTED = "已连接";
    //连接状态--未连接
    private final String NO_CONNECT = "未连接";
    //蓝牙适配器
    BluetoothAdapter mBluetoothAdapter = null;
    List<ScannedDevice> mScannedDevices = null;
    //扫描设备列表
    List<BluetoothDevice> mBluetoothDevices;
    //recyclerView 适配器
    RecyclerViewAdapter mAdapter = null;
    //发起连接的线程
    private ConnectThread connectThread;
    //管理连接的线程
    private ConnectedThread connectedThread;
    //蓝牙广播
    private CustomBroadcastReceiver broadcastReceiver;
    //扫描设备按钮
    Button btnScan;
    //开始采集按钮
    Button btnEEGOn;
    //停止采集按钮
    Button btnEEGOff;
    //设备状态
    TextView deviceStatus;
    //服务状态
    TextView serviceStatusEEG;
    //设备列表视图
    RecyclerView recycleView = null;
    //环境配置
    private String env;
    //用户信息--名称
    private String userName;
    //用户信息--手机号
    private String phoneNumber;
    //服务器地址
    private String serverIp;
    //临时数据buffer
    private StringBuffer dataBuffer;
    //用户手机号
    TextView tv_phone;
    //服务器状态
    TextView tv_server;
    //UUID 蓝牙通讯


    private final String UUID = "6E400003-b5A3-F393-E0A9-eE0E24DCCA9E";
    //蓝牙连接超时时间
    private final long conOutTime = 20000;
    //服务状态-连接
    private final int EVENT_SERVICE_CONNECT = 100;
    //服务状态-断开连接
    private final int EVENT_SERVICE_CONNECT_LOSE = 1001;
    //定时器
    private final Timer timer = new Timer();
    //开关
    boolean eegOn = false;
//    socket
    BluetoothSocket mBluetoothSocket;
    //图表线条名称
    private List<String> lineChartName = new ArrayList<>();

    //图表线条颜色
    private List<Integer> lineChartColor = new ArrayList<>();
    private ConcurrentLinkedQueue<Integer> rawDataQueue = new ConcurrentLinkedQueue<>();
    private ConcurrentLinkedQueue<Integer> deltaQueue = new ConcurrentLinkedQueue<>();
    private ConcurrentLinkedQueue<Integer> thetaQueue = new ConcurrentLinkedQueue<>();
    private ConcurrentLinkedQueue<Integer> lowAlphaQueue = new ConcurrentLinkedQueue<>();
    private ConcurrentLinkedQueue<Integer> highAlphaQueue = new ConcurrentLinkedQueue<>();
    private ConcurrentLinkedQueue<Integer> lowBetaQueue = new ConcurrentLinkedQueue<>();
    private ConcurrentLinkedQueue<Integer> highBetaQueue = new ConcurrentLinkedQueue<>();
    private ConcurrentLinkedQueue<Integer> lowGammaQueue = new ConcurrentLinkedQueue<>();
    private ConcurrentLinkedQueue<Integer> midGammaQueue = new ConcurrentLinkedQueue<>();

    private ConcurrentLinkedQueue<Integer> noiseQueue = new ConcurrentLinkedQueue<>();
    private ConcurrentLinkedQueue<Integer> attentionQueue = new ConcurrentLinkedQueue<>();
    private ConcurrentLinkedQueue<Integer> meditationQueue = new ConcurrentLinkedQueue<>();
    private ConcurrentLinkedQueue<Integer> signalQueue = new ConcurrentLinkedQueue<>();

    //数据集合
    List<Entry> deltaDataList = new ArrayList<>();
    List<Entry> thetaDataList = new ArrayList<>();
    List<Entry> lowAlphaDataList = new ArrayList<>();
    List<Entry> highAlphaDataList = new ArrayList<>();
    List<Entry> lowBetaDataList = new ArrayList<>();
    List<Entry> highBetaDataList = new ArrayList<>();
    List<Entry> lowGammaDataList = new ArrayList<>();
    List<Entry> midGammaDataList = new ArrayList<>();
    List<Entry> noiseDataList = new ArrayList<>();
    List<Entry> attentionDataList = new ArrayList<>();
    List<Entry> meditationDataList = new ArrayList<>();


    List<Integer> deltaDataListInteger = new ArrayList<>();
    List<Integer> thetaDataListInteger = new ArrayList<>();
    List<Integer> lowAlphaDataListInteger = new ArrayList<>();
    List<Integer> highAlphaDataListInteger = new ArrayList<>();
    List<Integer> lowBetaDataListInteger = new ArrayList<>();
    List<Integer> highBetaDataListInteger = new ArrayList<>();
    List<Integer> lowGammaDataListInteger = new ArrayList<>();
    List<Integer> midGammaDataListInteger = new ArrayList<>();
    List<Integer> noiseDataListInteger = new ArrayList<>();
    List<Integer> attentionDataListInteger = new ArrayList<>();
    List<Integer> meditationDataListInteger = new ArrayList<>();
    LineChart chart; // 折线表，存线集合
    LineData mLineData; // 线集合，所有折现以数组的形式存到此集合中
    XAxis mXAxis; //X轴
    YAxis mLeftYAxis; //左侧Y轴
    YAxis mRightYAxis; //右侧Y轴
    LimitLine mLimitline; //限制线

    //数据采集状态
    private boolean collectData = false;

    private static final int CONNECT_SUCCESS = 0x01;
    private static final int START_DISCOVERY = 0x08;
    private static final int STOP_DISCOVERY = 0x09;
    private static final int DISCOVERY_DEVICE = 0x0A;
    private static final int CONNECT_FAILURE = 0x02;
    private static final int DISCONNECT_SUCCESS = 0x03;
    private static final int SEND_SUCCESS = 0x04;
    private static final int SEND_FAILURE= 0x05;
    private static final int RECEIVE_SUCCESS= 0x06;
    private static final int RECEIVE_FAILURE =0x07;
    //解析数据
    Timer parseDataTimer ;

    Timer fillDataTimer;
    //已连接设备信息
    BluetoothDevice mBluetoothDevice;
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_e_e_g);
        initView();
        //设置点击事件
        btnScan = findViewById(R.id.btn_eeg_scan);
        btnScan.setOnClickListener(this);
        btnEEGOn = findViewById(R.id.btn_eeg_on);
        btnEEGOn.setOnClickListener(this);
        btnEEGOff = findViewById(R.id.btn_eeg_off);
        btnEEGOff.setOnClickListener(this);
        userName = getIntent().getStringExtra("userName");
        phoneNumber = getIntent().getStringExtra("phoneNumber");
        env = getIntent().getStringExtra("env");
        serverIp = getIntent().getStringExtra("serverIP");
        tv_phone = findViewById(R.id.tv_userInfo_eeg);
        tv_phone.setText(phoneNumber);
        tv_server = findViewById(R.id.serviceStatusEEG);
        tv_server.setText("已连接");
        deviceStatus = findViewById(R.id.tv_device_status);

        //初始化蓝牙广播
        initBroadcast();
        //检测服务状态
        //创建一个线程
        if(!Objects.equals(env, "TEST")){
            new Thread(() -> {
                //延迟两秒
                try {
                    Thread.sleep( 1000 );
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                runOnUiThread(() -> {
                    TimerTask testTimeLong = new TimerTask() {
                        @Override
                        public void run() {
                            serviceCheck();
                        }
                    };
                    timer.schedule(testTimeLong,1000,10000);
                });

            }).start();
        }

        //图表
        chart = findViewById(R.id.dynamic_chart_eeg);
//        chart.setOnChartValueSelectedListener(this);
        chart.setDrawGridBackground(false);
        chart.getDescription().setText("脑电采集");
//        chart.getDescription().setEnabled(true);
        chart.setNoDataText("No chart data available. Use the menu to add entries and data sets!");
        chart.invalidate();
//        线条名称
        lineChartName.add("Delta");
        lineChartName.add("Theta");
        lineChartName.add("Low Alpha");
        lineChartName.add("High Alpha");
        lineChartName.add("Low Beta");
        lineChartName.add("High Beta");
        lineChartName.add("Low Gamma");
        lineChartName.add("Mid Gamma");
        lineChartName.add("Noise");
        lineChartName.add("Attention");
        lineChartName.add("Meditation");
//        线条颜色
        lineChartColor.add(Color.GRAY);
        lineChartColor.add(Color.DKGRAY);
        lineChartColor.add(Color.YELLOW);
        lineChartColor.add(Color.GREEN);
        lineChartColor.add(Color.BLACK);
        lineChartColor.add(Color.BLUE);
        lineChartColor.add(Color.CYAN);
        lineChartColor.add(Color.MAGENTA);
        lineChartColor.add(Color.LTGRAY);
        lineChartColor.add(Color.RED);
        lineChartColor.add(Color.TRANSPARENT);
        addDataSet();

/*        Timer addDataTimer = new Timer("addData");
        addDataTimer.schedule(new TimerTask() {
            @Override
            public void run() {
                addEntry();
            }
        }, 1000, 1000);*/

    }

    private void addEntry() {
        int maxNum = 0;
        int minNum = 0;
        LineData data = chart.getData();
        // choose a random dataSet
        int poll;
        if(deltaQueue.size()>0){
          ILineDataSet set = data.getDataSetByIndex(0);
          poll = deltaQueue.poll();
          data.addEntry(new Entry(set.getEntryCount(),poll), 0);
          if(deltaDataListInteger.size()==30){
              deltaDataListInteger.remove(0);
          }
          deltaDataListInteger.add(poll);
            for (Integer i:deltaDataListInteger) {
                if(i>maxNum){
                    maxNum = i;
                }
                if(i<minNum){
                    minNum = i;
                }
            }

        }
        if(thetaQueue.size()>0){
            ILineDataSet set = data.getDataSetByIndex(1);
            poll = thetaQueue.poll();
            data.addEntry(new Entry(set.getEntryCount(),poll), 1);
            if(thetaDataListInteger.size()==30){
                thetaDataListInteger.remove(0);
            }
            thetaDataListInteger.add(poll);
            for (Integer i:thetaDataListInteger) {
                if(i>maxNum){
                    maxNum = i;
                }
                if(i<minNum){
                    minNum = i;
                }
            }
        }
        if(lowAlphaQueue.size()>0){
            ILineDataSet set = data.getDataSetByIndex(2);
            poll = lowAlphaQueue.poll();
            data.addEntry(new Entry(set.getEntryCount(),poll), 2);
            if(lowAlphaDataListInteger.size()==30){
                lowAlphaDataListInteger.remove(0);
            }
            lowAlphaDataListInteger.add(poll);
            for (Integer i:lowAlphaDataListInteger) {
                if(i>maxNum){
                    maxNum = i;
                }
                if(i<minNum){
                    minNum = i;
                }
            }
        }
        if(highAlphaQueue.size()>0){
            ILineDataSet set = data.getDataSetByIndex(2);
            poll = highAlphaQueue.poll();
            data.addEntry(new Entry(set.getEntryCount(),poll), 3);
            if(highAlphaDataListInteger.size()==30){
                highAlphaDataListInteger.remove(0);
            }
            highAlphaDataListInteger.add(poll);
            for (Integer i:highAlphaDataListInteger) {
                if(i>maxNum){
                    maxNum = i;
                }
                if(i<minNum){
                    minNum = i;
                }
            }
        }
        if(lowBetaQueue.size()>0){
            ILineDataSet set = data.getDataSetByIndex(4);
            poll =lowBetaQueue.poll();
            data.addEntry(new Entry(set.getEntryCount(),poll), 4);
            if(lowBetaDataListInteger.size()==30){
                lowBetaDataListInteger.remove(0);
            }
            lowBetaDataListInteger.add(poll);
            for (Integer i:lowBetaDataListInteger) {
                if(i>maxNum){
                    maxNum = i;
                }
                if(i<minNum){
                    minNum = i;
                }
            }
        }
        if(highBetaQueue.size()>0){
            ILineDataSet set = data.getDataSetByIndex(5);
            poll = highBetaQueue.poll();
            data.addEntry(new Entry(set.getEntryCount(),poll), 5);
            if(highBetaDataListInteger.size()==30){
                highBetaDataListInteger.remove(0);
            }
            highBetaDataListInteger.add(poll);
            for (Integer i:highBetaDataListInteger) {
                if(i>maxNum){
                    maxNum = i;
                }
                if(i<minNum){
                    minNum = i;
                }
            }
        }
        if(lowGammaQueue.size()>0){
            ILineDataSet set = data.getDataSetByIndex(6);
            poll =lowGammaQueue.poll();
            data.addEntry(new Entry(set.getEntryCount(),poll), 6);
            if(lowGammaDataListInteger.size()==30){
                lowGammaDataListInteger.remove(0);
            }
            lowGammaDataListInteger.add(poll);
            for (Integer i:lowGammaDataListInteger) {
                if(i>maxNum){
                    maxNum = i;
                }
                if(i<minNum){
                    minNum = i;
                }
            }
        }
        if(midGammaQueue.size()>0){
            ILineDataSet set = data.getDataSetByIndex(7);
            poll = midGammaQueue.poll();
            data.addEntry(new Entry(set.getEntryCount(),poll), 7);
            if(midGammaDataListInteger.size()==30){
                midGammaDataListInteger.remove(0);
            }
            midGammaDataListInteger.add(poll);
            for (Integer i:midGammaDataListInteger) {
                if(i>maxNum){
                    maxNum = i;
                }
                if(i<minNum){
                    minNum = i;
                }
            }
        }
        if(noiseQueue.size()>0){
            ILineDataSet set = data.getDataSetByIndex(8);
            poll = noiseQueue.poll();
            data.addEntry(new Entry(set.getEntryCount(),poll), 8);
            if(noiseDataListInteger.size()==30){
                noiseDataListInteger.remove(0);
            }
            noiseDataListInteger.add(poll);
            for (Integer i:noiseDataListInteger) {
                if(i>maxNum){
                    maxNum = i;
                }
                if(i<minNum){
                    minNum = i;
                }
            }
        }
        if(attentionQueue.size()>0){
            ILineDataSet set = data.getDataSetByIndex(9);
            poll = attentionQueue.poll();
            data.addEntry(new Entry(set.getEntryCount(),poll), 9);
            if(attentionDataListInteger.size()==30){
                attentionDataListInteger.remove(0);
            }
            attentionDataListInteger.add(poll);
            for (Integer i:attentionDataListInteger) {
                if(i>maxNum){
                    maxNum = i;
                }
                if(i<minNum){
                    minNum = i;
                }
            }
        }
        if(meditationQueue.size()>0){
            ILineDataSet set = data.getDataSetByIndex(10);
            poll = meditationQueue.poll();
            data.addEntry(new Entry(set.getEntryCount(),poll), 10);
            if(meditationDataListInteger.size()==30){
                meditationDataListInteger.remove(0);
            }
            meditationDataListInteger.add(poll);
            for (Integer i:meditationDataListInteger) {
                if(i>maxNum){
                    maxNum = i;
                }
                if(i<minNum){
                    minNum = i;
                }
            }
        }
        data.notifyDataChanged();

        // let the chart know it's data has changed
        chart.notifyDataSetChanged();

        chart.setVisibleXRangeMaximum(10);
        chart.setVisibleYRangeMaximum(maxNum-minNum+10, YAxis.AxisDependency.LEFT);
        chart.getXAxis().setPosition(XAxis.XAxisPosition.BOTTOM);
        chart.getXAxis().setDrawAxisLine(true);
        chart.getXAxis().setDrawGridLines(true);
        chart.getXAxis().setLabelCount(10, false);
        chart.getAxisLeft().setAxisMinimum(minNum);
        chart.getAxisLeft().setAxisMaximum(maxNum);
        chart.getAxisLeft().setGranularity(10);
        chart.getAxisLeft().setDrawZeroLine(true);
        chart.getAxisLeft().setEnabled(true);
        chart.getAxisRight().setEnabled(false);
        chart.getAxisLeft().setLabelCount((maxNum-minNum)/10000+1);
        // this automatically refreshes the chart (calls invalidate())
        chart.moveViewTo(data.getEntryCount() - 11, 50f, YAxis.AxisDependency.LEFT);

    }

    private void addDataSet() {
           LineData data = chart.getData();
           if(data == null){
               data = new LineData();
               chart.setData(data);
           }
        deltaDataList.add(new Entry(0,0));
        LineDataSet deltaDataSet = new LineDataSet(deltaDataList,"Delta");
        deltaDataSet.setColor(lineChartColor.get(0));
        data.addDataSet(deltaDataSet);
        thetaDataList.add(new Entry(0,0));
        LineDataSet thetaDataSet = new LineDataSet(thetaDataList,"Theta");
        thetaDataSet.setColor(lineChartColor.get(1));
        data.addDataSet(thetaDataSet);
        lowAlphaDataList.add(new Entry(0,0));
        LineDataSet lowAlphaDataSet = new LineDataSet(lowAlphaDataList, "Low Alpha");
        lowAlphaDataSet.setColor(lineChartColor.get(2));
        data.addDataSet(lowAlphaDataSet);
        highAlphaDataList.add(new Entry(0, 0));
        LineDataSet highAlphaDataSet = new LineDataSet(highAlphaDataList, "High Alpha");
        highAlphaDataSet.setColor(lineChartColor.get(3));
        data.addDataSet(highAlphaDataSet);
        lowBetaDataList.add(new Entry(0, 0));
        LineDataSet lowBetaDataSet = new LineDataSet(lowBetaDataList, "LowBeta");
        lowBetaDataSet.setColor(lineChartColor.get(4));
        data.addDataSet(lowBetaDataSet);
        highBetaDataList.add(new Entry(0, 0));
        LineDataSet highBetaDataSet = new LineDataSet(highBetaDataList, "High Beta");
        highBetaDataSet.setColor(lineChartColor.get(5));
        data.addDataSet(highBetaDataSet);
        lowGammaDataList.add(new Entry(0, 0));
        LineDataSet lowGammaDataSet = new LineDataSet(lowGammaDataList, "Low Gamma");
        lowGammaDataSet.setColor(lineChartColor.get(6));
        data.addDataSet(lowGammaDataSet);
        midGammaDataList.add(new Entry(0, 0));
        LineDataSet midGammaDataSet = new LineDataSet(midGammaDataList, "Mid Gamma");
        midGammaDataSet.setColor(lineChartColor.get(7));
        data.addDataSet(midGammaDataSet);
        noiseDataList.add(new Entry(0, 0));
        LineDataSet noiseDataSet = new LineDataSet(noiseDataList, "Noise");
        noiseDataSet.setColor(lineChartColor.get(8));

        data.addDataSet(noiseDataSet);
        attentionDataList.add(new Entry(0, 0));
        LineDataSet attentionDataSet = new LineDataSet(attentionDataList, "Attention");
        attentionDataSet.setColor(lineChartColor.get(9));
        data.addDataSet(attentionDataSet);
        meditationDataList.add(new Entry(0, 0));
        LineDataSet meditationDataSet = new LineDataSet(meditationDataList, "Meditation");
        meditationDataSet.setColor(lineChartColor.get(10));
        data.addDataSet(meditationDataSet);
//           data.notifyDataChanged();
//           chart.notifyDataSetChanged();
//           chart.invalidate();

    }

    /**
     * 解析数据，并将数据放入对应的队列
     */
    private void parseData(){
        byte[] dataBytes;
        boolean bigPkg = false;
        Log.d(TAG, "dataBuffer.length()---"+dataBuffer.length());
        if(dataBuffer.length()>72){
            if(!dataBuffer.substring(0,2).equals("AA") || !dataBuffer.substring(2,4).equals("AA")){
                //clear dataBuffer
                dataBuffer.setLength(0);
            }else {
                if(dataBuffer.substring(4,6).equals("04")){
                    //small pkg
                    dataBytes = hexString2Bytes(dataBuffer.substring(0,16));
                    dataBuffer.delete(0,16);
                }else {
                    //big pkg
                    dataBytes = hexString2Bytes(dataBuffer.substring(0,72));
                    dataBuffer.delete(0, 72);
                    bigPkg = true;
                }
                if(checkSum( bigPkg, dataBytes)){
                    return;
                }
                if(bigPkg){
//                    Log.d(TAG, "-----------------big pkg ---------------------");
                    //signal
                    signalQueue.add((dataBytes[4])&0xff);

                    //delta
                    deltaQueue.add(dataBytes[7]<<16|dataBytes[8]<<8|dataBytes[9]);
                    //theta
                    thetaQueue.add(dataBytes[10]<<16|dataBytes[11]<<8|dataBytes[12]);
                    //lowAlpha
                    lowAlphaQueue.add(dataBytes[13]<<16|dataBytes[14]<<8|dataBytes[15]);
                    //highAlpha
                    highAlphaQueue.add(dataBytes[16]<<16|dataBytes[17]<<8|dataBytes[18]);
                    //lowBeta
                    lowBetaQueue.add(dataBytes[19]<<16|dataBytes[20]<<8|dataBytes[21]);
                    //highBeta
                    highBetaQueue.add(dataBytes[22]<<16|dataBytes[23]<<8|dataBytes[24]);
                    //lowGamma
                    lowGammaQueue.add(dataBytes[25]<<16|dataBytes[26]<<8|dataBytes[27]);
                    //midGamma
                    midGammaQueue.add(dataBytes[28]<<16|dataBytes[29]<<8|dataBytes[30]);
                    //attention
                    attentionQueue.add((dataBytes[32])&0xff);
                    //meditation
                    meditationQueue.add((dataBytes[34])&0xff);
                }else {
                    getRawData(dataBytes[5],dataBytes[6]);
                }
            }
        }else {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
    private void getRawData(byte dataByteHigh, byte dataByteLow) {
        int rawData = (dataByteHigh << 8) | dataByteLow;
        if(rawData > 32768){
            rawData -= 65536;
        }
        if(rawDataQueue.size()>=512){
            rawDataQueue.poll();
        }
        rawDataQueue.add(rawData);
    }

    private boolean checkSum(boolean bigPkg,byte[] dataBytes){
        if (bigPkg){
            return ((~(dataBytes[3] + dataBytes[4] + dataBytes[5] + dataBytes[6])) & 0xff) == dataBytes[7];
        }else {
            return (dataBytes[0] & 0xff) == 0xaa &&
                    (dataBytes[1] & 0xff) == 0xaa &&
                    (dataBytes[2] & 0xff) == 0x20 &&
                    (dataBytes[3] & 0xff) == 0x02 &&
                    (dataBytes[5] & 0xff) == 0x83 &&
                    (dataBytes[6] & 0xff) == 0x18 &&
                    (dataBytes[31] & 0xff) == 0x04 &&
                    (dataBytes[33] & 0xff) == 0x05;
        }
    }

    //服务状态检测
    public void serviceCheck(){
        int port = 8082;
        if(env.equals("ZB")){
            port = 8081;
        } else if (env.equals("ccy")) {
            port = 8109;
        }
        boolean result = ServerUtil.isPortUseful2(serverIp, port, 5000,"");
        if ( result){
            handler.sendEmptyMessage(EVENT_SERVICE_CONNECT);
        }else{
            handler.sendEmptyMessage(EVENT_SERVICE_CONNECT_LOSE);
        }
    }
    @Override
    public void onClick(View view) {
        Log.i(TAG,view.toString());
        if(view.getId() !=  R.id.btn_eeg_scan && view.getId() != R.id.btn_eeg_on && view.getId() != R.id.btn_eeg_off){
            //判断是否连接设备
            if(!isConnected){
                Toast.makeText(this, "未连接设备", Toast.LENGTH_SHORT).show();
            }
        }
        /*switch (view.getId()){
            case R.id.btn_eeg_scan:
//                scanLeDevice();
                scanDevice();
            break;
            case R.id.btn_eeg_on:
                eegOn();
                break;
            case R.id.btn_eeg_off:
                eegOff();
                break;
        }*/
        //Android Gradle 5.0之后控件id将不再是final，switch case中switch字段必须是final加持，因此需使用if else 替换 switch case
        if(view.getId() == R.id.btn_eeg_scan){
            scanDevice();
        }else if(view.getId() == R.id.btn_eeg_on){
            eegOn();
        } else if (view.getId() == R.id.btn_eeg_off) {
            eegOff();
        }else {
            Log.d(TAG, "invalid click");
        }
    }
    //扫描经典蓝牙,经典蓝牙的扫描可以兼容低功耗蓝牙的扫描
    private void scanDevice() {
        Log.i(TAG,"开始扫描经典蓝牙");
        btnScan.setEnabled(false);
        if(mBluetoothAdapter == null){
            mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        }
        if(mBluetoothAdapter.isDiscovering()){//正在扫描
            return;
        }
        if(mScannedDevices == null){
            mScannedDevices = new ArrayList<>();
        }else{
            mScannedDevices.clear();
        }

        if(mBluetoothDevices == null){
            mBluetoothDevices = new ArrayList<>();
        }else{
            mBluetoothDevices.clear();
        }
        //开始扫描
        mBluetoothAdapter.startDiscovery();
        handler.postDelayed(() -> mBluetoothAdapter.cancelDiscovery(),10000);
    }

    //停止采集
    private void eegOff() {
        clearConnectedThread();
        Log.d(TAG, "即将停止数据解析调度任务");
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        if(parseDataTimer != null)
            parseDataTimer.cancel();
        if(fillDataTimer != null)
            fillDataTimer.cancel();
//        chart.invalidate();
    }

    //开始采集
    private void eegOn() {
        if(!isConnected){
            Toast.makeText(this, "请先连接设备", Toast.LENGTH_SHORT).show();
            return;
        }
        eegOn = true;
        //重连
        connectDevice(mBluetoothDevice);

        //管理连接收发数据
        managerConnectReceiveData(mBluetoothSocket);

        //启动定时器，解析数据,避免重新开始时Timer already cancelled,每次开启数据收集时都重新创建Timer
        parseDataTimer = new Timer("parseData");
        Log.d(TAG, "开启数据解析调度任务");
        parseDataTimer.schedule(new TimerTask() {
            @Override
            public void run() {
                parseData();
            }
        }, 500,1);

        Log.d(TAG, "开启数据曲线填充调度任务");
        fillDataTimer = new Timer("fillData");
        fillDataTimer.schedule(new TimerTask() {
            @Override
            public void run() {
//                fillData();
                addEntry();
            }
        }, 1000, 1000);


    }

    /**
     * 填充数据
     */
    private void fillData() {
        try{
            LineData data = chart.getData();
            if(deltaQueue.size()>0){

                Integer delta = deltaQueue.poll();

                Entry entry = new Entry(data.getDataSets().get(0).getEntryCount(), delta);
                data.addEntry(entry,0);
                data.notifyDataChanged();
                chart.notifyDataSetChanged();
                chart.setVisibleXRangeMaximum(10);
                chart.setVisibleYRangeMaximum(100, YAxis.AxisDependency.LEFT);
                chart.moveViewTo(Math.max(data.getEntryCount() - 10, 0), 50f, YAxis.AxisDependency.LEFT);

            }
        }catch (Exception e ){
            e.printStackTrace();
        }





    }

    //连接设备
    private void connectDevice(BluetoothDevice bluetoothDevice){
        if(isConnected){
            Toast.makeText(this,"已连接设备",Toast.LENGTH_SHORT).show();
        }else{
            startConnectDevice(bluetoothDevice);
        }

    }
    //连接蓝牙设备
    private void startConnectDevice(BluetoothDevice bluetoothDevice) {
        connectThread = new ConnectThread(mBluetoothAdapter,bluetoothDevice,UUID);
        connectThread.setOnBluetoothConnectListener(new ConnectThread.OnBluetoothConnectListener() {
            @Override
            public void onStartConn() {
                Log.i(TAG,"startConnectDevice-->开始连接..." + bluetoothDevice.getName() + "-->" + bluetoothDevice.getAddress());
            }

            @Override
            public void onConnSuccess(BluetoothSocket bluetoothSocket) {
                //移除连接超时
                handler.removeCallbacks(connectOutTimeRunnable);
                Log.d(TAG,"startConnectDevice-->移除连接超时");
                Log.w(TAG,"startConnectDevice-->连接成功");
                Message message  = new Message();
                message.what = CONNECT_SUCCESS;
                message.obj = bluetoothDevice;
                handler.sendMessage(message);
                isConnected = true;
                //将收发数据放到开始采集
                //管理连接收发数据
                mBluetoothSocket = bluetoothSocket;
//                managerConnectReceiveData(bluetoothSocket);
            }

            @Override
            public void onConnFailure(String errorMsg) {
                Log.i(TAG,"startConnectDevice-->" + errorMsg);

                Message message = new Message();
                message.what = CONNECT_FAILURE;
                handler.sendMessage(message);
                //标记当前连接状态为false
                isConnected = false;
                //断开管理连接
                clearConnectedThread();
            }
        });
        connectThread.start();
        //设置连接超时时间
        handler.postDelayed(connectOutTimeRunnable,conOutTime);
    }
    //管理已经建立的连接，收发数据
    private void managerConnectReceiveData(BluetoothSocket bluetoothSocket) {
        //管理已有链接
        connectedThread =  new ConnectedThread(bluetoothSocket);
        connectedThread.start();
        connectedThread.setOnSendReceiveDataListener(new ConnectedThread.OnSendReceiveDataListener(){

            @Override
            public void onSendDataSuccess(byte[] data) {
                Log.i(TAG,"发送数据，长度"+data.length+"->"+bytes2HexString(data,data.length));
                Message message = new Message();
                message.what = SEND_SUCCESS;
                message.obj = "发送数据，长度"+data.length+"->"+bytes2HexString(data,data.length);
                handler.sendMessage(message);
            }

            @Override
            public void onSendDataError(byte[] data, String errorMsg) {
                Log.e(TAG,"发送数据出错,长度" + data.length + "->" + bytes2HexString(data,data.length));
                Message message = new Message();
                message.what = SEND_FAILURE;
                message.obj = "发送数据出错,长度" + data.length + "->" + bytes2HexString(data,data.length);
                handler.sendMessage(message);
            }

            @SuppressLint("SimpleDateFormat")
            @Override
            public void onReceiveDataSuccess(byte[] buffer) {
                Message message = new Message();
                message.what = RECEIVE_SUCCESS;
                message.obj =  bytes2HexString(buffer,buffer.length);
                handler.sendMessage(message);
            }

            @Override
            public void onReceiveDataError(String errorMsg) {
                Log.e(TAG,"接收数据出错：" + errorMsg);
                Message message = new Message();
                message.what = RECEIVE_FAILURE;
                message.obj = "接收数据出错：" + errorMsg;
                handler.sendMessage(message);
            }
        });
    }

    ///////////////////////////////   数据类型转换  //////////////////////////////////////////////
    /**
     * 字节数组-->16进制字符串
     * @param b   字节数组
     * @param length  字节数组长度
     * @return 16进制字符串 有空格类似“0A D5 CD 8F BD E5 F8”
     */
    public static String bytes2HexString(byte[] b, int length) {
        StringBuffer result = new StringBuffer();
        String hex;
        for (int i = 0; i < length; i++) {
            hex = Integer.toHexString(b[i] & 0xFF);
            if (hex.length() == 1) {
                hex = '0' + hex;
            }
            result.append(hex.toUpperCase()).append(" ");
        }
        return result.toString().replace(" ","");
    }

    /**
     * hexString2Bytes
     * 16进制字符串-->字节数组
     * @param src  16进制字符串
     * @return 字节数组
     */
    public static byte[] hexString2Bytes(String src) {
        int l = src.length() / 2;
        byte[] ret = new byte[l];
        for (int i = 0; i < l; i++) {
            ret[i] = Integer
                    .valueOf(src.substring(i * 2, i * 2 + 2), 16).byteValue();
        }
        return ret;
    }


    ///////////////////////////////////////////////////////////////////////////////////////////////
    //连接超时
        private Runnable connectOutTimeRunnable = new Runnable() {
        @Override
        public void run() {
            Log.e(TAG,"startConnectDevice--->连接超时");
            Message message = new Message();
            message.what = CONNECT_FAILURE;
            handler.sendMessage(message);
            isConnected = false;
            clearConnectedThread();
        }
    };
    private void clearConnectedThread() {
        Log.i(TAG,"clearConnectedThread-->即将断开");

        //connectedThread断开已有连接
        if(connectedThread == null){
            Log.i(TAG,"clearConnectedThread-->connectedThread == null");
            return;
        }
        connectedThread.terminalClose(connectThread);

        //等待线程运行完后再断开
        handler.postDelayed(() -> {
            connectedThread.cancel();  //释放连接

            connectedThread = null;
        },10);

        Log.w(TAG,"clearConnectedThread-->成功断开连接");
        Message message = new Message();
        message.what = DISCONNECT_SUCCESS;
        handler.sendMessage(message);
    }

    //扫描结果回调

    //初始化
    private void initView (){

        setSupportActionBar(findViewById(R.id.toolbarEEG));
        recycleView =  findViewById(R.id.recycler_view_eeg);
        recycleView.setLayoutManager(new LinearLayoutManager(this,LinearLayoutManager.VERTICAL,false));
        LinearSnapHelper linearSnapHelper = new LinearSnapHelper();
        linearSnapHelper.attachToRecyclerView(recycleView);
        mScannedDevices = new ArrayList<>();
        mAdapter = new RecyclerViewAdapter(mScannedDevices);
        recycleView.setAdapter(mAdapter);
        mAdapter.setItemClickListener((view, position) -> {

            mBluetoothDevice = mBluetoothDevices.get(position);
            Log.i(TAG,"点击设备");
            Toast.makeText(EEGActivity.this,"开始连接设备——"+mBluetoothDevice.getName()+"——"+mBluetoothDevice.getAddress(),Toast.LENGTH_SHORT).show();
            //点击设备列表后停止扫描设备
            Message message = new Message();
            message.what = STOP_DISCOVERY;
            handler.sendMessage(message);
            connectDevice(mBluetoothDevice);
        });
    }
    private final Handler handler = new Handler(){
        @SuppressLint("ResourceType")
        @Override
        public void handleMessage(Message message) {
            switch(message.what){
                case 100: //服务连接
                    tv_server.setText(CONNECTED);
                    tv_server.setTextColor(Color.parseColor(getString(Color.GREEN)));
                    break;
                case 1001://服务断开连接
                    tv_server.setText(NO_CONNECT);
                    tv_server.setTextColor(Color.parseColor(getString(Color.BLACK)));
                    break;
                case STOP_DISCOVERY:
                    Log.d(TAG,"停止搜索设备");
                    btnScan.setEnabled(true);
                    break;
                case DISCOVERY_DEVICE:
                    Log.i(TAG,"发现设备");
                    ScannedDevice scannedDevice = (ScannedDevice) message.obj;
                    int index = mScannedDevices.indexOf(scannedDevice);
                    if(index == -1){
                        mScannedDevices.add(scannedDevice);
                    }else{
                        mScannedDevices.get(index).setRssi(scannedDevice.getRssi());
                    }

                    mAdapter.notifyDataSetChanged();
                    break;
                case CONNECT_SUCCESS :
                    BluetoothDevice mBluetoothDevice = (BluetoothDevice) message.obj;
                    Toast.makeText(EEGActivity.this,"设备"+mBluetoothDevice.getName()+"已连接",Toast.LENGTH_SHORT).show();
                     deviceStatus.setText( CONNECTED);
                    break;
                case SEND_SUCCESS:
                    Log.i(TAG,"数据发送成功");
                    break;
                case RECEIVE_SUCCESS:
                    if(dataBuffer == null){
                        dataBuffer = new StringBuffer();
                    }
                    String data = (String) message.obj;
                    if(eegOn) dataBuffer.append(data);
                    break;
                case DISCONNECT_SUCCESS:
                    isConnected = false;
                    break;
                case CONNECT_FAILURE:
                    Toast.makeText(EEGActivity.this, "链接失败，请检查设备状态！", Toast.LENGTH_SHORT);
            }
        }
    };
    //初始化蓝牙广播
    private void initBroadcast(){
        broadcastReceiver = new CustomBroadcastReceiver();
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED); //开始扫描
        intentFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);//扫描结束
        intentFilter.addAction(BluetoothDevice.ACTION_FOUND);//搜索到设备
        intentFilter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED); //配对状态监听
        registerReceiver(broadcastReceiver,intentFilter);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        //注销广播接收
        unregisterReceiver(broadcastReceiver);
        if(parseDataTimer != null) parseDataTimer.cancel();
        if(fillDataTimer != null) fillDataTimer.cancel();
    }

    //    蓝牙广播接收器
    private class CustomBroadcastReceiver extends BroadcastReceiver{

    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if(action.equals(BluetoothAdapter.ACTION_DISCOVERY_STARTED)){//开始搜索
            Log.i(TAG,"开始搜索设备");
            Message message = new Message();
            message.what = START_DISCOVERY;
            handler.sendMessage(message);
        }else if(TextUtils.equals(action,BluetoothAdapter.ACTION_DISCOVERY_FINISHED)){//完成搜索
            Log.i(TAG,"停止搜索");
            Message message = new Message();
            message.what = STOP_DISCOVERY;
            handler.sendMessage(message);
        }else if(TextUtils.equals(action,BluetoothDevice.ACTION_FOUND)){//搜索到设备
            //蓝牙设备
            BluetoothDevice bluetoothDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
            //信号强度
            int rssi = intent.getShortExtra(BluetoothDevice.EXTRA_RSSI,Short.MIN_VALUE);
            Log.i(TAG,"扫描到设备："+bluetoothDevice.getName()+"___"+bluetoothDevice.getAddress()+"___"+String.valueOf(rssi));
            if(bluetoothDevice.getName() == null) return;
            if(!bluetoothDevice.getName().contains("MIND")) return;
            Message message = new Message();
            message.what = DISCOVERY_DEVICE;
            ScannedDevice mScannedDevice = new ScannedDevice(bluetoothDevice.getName(),bluetoothDevice.getAddress(),rssi);
            message.obj = mScannedDevice;
            handler.sendMessage(message);
            mBluetoothDevices.add(bluetoothDevice);
        }
    }
}
    static class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder> {

        private static final String TAG = "RecyclerViewAdapter";
        private List<ScannedDevice> localDataSet;
        private OnItemClickListener itemClickListener;

        /**
         * Provide a reference to the type of views that you are using
         * (custom ViewHolder).
         */
          class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
            private final TextView deviceName;
            private final TextView deviceAddress;
            private final TextView rssi;
            private OnItemClickListener onItemClickListener;
            public ViewHolder(View view ,OnItemClickListener listener) {
                super(view);
                // Define click listener for the ViewHolder's View
                onItemClickListener = listener;
                view.setOnClickListener(this);
                deviceName = view.findViewById(R.id.tv_name);
                deviceAddress = view.findViewById(R.id.tv_mac);
                rssi = view.findViewById(R.id.tv_rssi);
            }

            public TextView getDeviceAddress() {
                return deviceAddress;
            }

            public TextView getDeviceName() {
                return deviceName;
            }

            public TextView getRssi() {
                return rssi;
            }

            @Override
            public void onClick(View view) {
                onItemClickListener.onItemClick(view,getAdapterPosition());
            }
        }

        /**
         * Initialize the dataset of the Adapter.
         *
         * @param scannedDevices list containing the data to populate views to be used
         * by RecyclerView.
         */
        public RecyclerViewAdapter(List<ScannedDevice> scannedDevices) {
            localDataSet = scannedDevices;
        }

        // Create new views (invoked by the layout manager)
        @Override
        public RecyclerViewAdapter.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
            // Create a new view, which defines the UI of the list item
            View view = LayoutInflater.from(viewGroup.getContext())
                    .inflate(R.layout.item_scan_result, viewGroup, false);
            ViewHolder viewHolder = new ViewHolder(view,itemClickListener);
            return viewHolder;
        }


        // Replace the contents of a view (invoked by the layout manager)
        @Override
        public void onBindViewHolder(RecyclerViewAdapter.ViewHolder viewHolder, @SuppressLint("RecyclerView") final int position) {
            int index = position;
            // Get element from your dataset at this position and replace the
            // contents of the view with that element
            Log.i(TAG, "onBindViewHolder: name-"+localDataSet.get(position).getName()+"  address:"+localDataSet.get(position).getAddress()+"  rssi:"+localDataSet.get(position).getRssi());
            viewHolder.getDeviceName().setText(localDataSet.get(position).getName());
            viewHolder.getDeviceAddress().setText(localDataSet.get(position).getAddress());
            viewHolder.getRssi().setText(String.valueOf(localDataSet.get(position).getRssi()));
        }

        // Return the size of your dataset (invoked by the layout manager)
        @Override
        public int getItemCount() {
            return localDataSet == null?0:localDataSet.size();
        }

        //点击事件接口
         public interface OnItemClickListener{
            public void onItemClick( View view,int position);
        }
        //设置点击事件的方法
        public void setItemClickListener(OnItemClickListener itemClickListener){
            this.itemClickListener = itemClickListener;
        }
    }
}
